/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "imageButton.h"
#include "menu.h"
#include "text.h"
#include "textureContainer.h"

namespace Graph2D
{
	ImageButton::ImageButton()
		: leftFrameSize(0)
		, rightFrameSize(0)
		, clickEvent(NULL)
	{
		setType(TYPE_IMAGE_BUTTON);

		//pageSize = 1;
		memset(frameTexture, NULL, sizeof(frameTexture));

		setFrameStyle(FRAME_STYLE_NOLINE|FRAME_STYLE_FLAT);
		setColor(1, 1, 1, 1, 0);
		setTouchable(true);
	}

	float ImageButton::getWidth() const
	{
		return getSize().x;
	}

	void ImageButton::setWidth(const float width)
	{
		setSize(width, getSize().y);
	}

	bool ImageButton::loadFrameTexture(const ImageButton::Direction direction, const std::string& filename, const bool pushed)
	{
		TextureContainer& builder = TextureContainer::getInstance();
		builder.unload(frameTexture[direction][pushed ? 1 : 0]);
		frameTexture[direction][pushed ? 1 : 0] = builder.load(filename);
		return frameTexture[direction][pushed ? 1 : 0] != NULL;
	}

	void ImageButton::unloadFrameTexture(const ImageButton::Direction direction, const bool pushed)
	{
		TextureContainer& builder = TextureContainer::getInstance();
		builder.unload(frameTexture[direction][pushed ? 1 : 0]);
		frameTexture[direction][pushed ? 1 : 0] = NULL;
	}

	const Vector2& ImageButton::getFrameTexCoord(const ImageButton::Direction direction, const bool pushed) const
	{
		return frameTexCoord[direction][pushed ? 1 : 0];
	}

	void ImageButton::setFrameTexCoord(const ImageButton::Direction direction, const Vector2& frameTexCoord, const bool pushed)
	{
		this->frameTexCoord[direction][pushed ? 1 : 0] = frameTexCoord;
	}

	void ImageButton::setFrameTexCoord(const ImageButton::Direction direction, const float u, const float v, const bool pushed)
	{
		setFrameTexCoord(direction, Vector2(u, v), pushed);
	}

	void ImageButton::onSerialize(mana_stream* stream) const
	{
		super::onSerialize(stream);
		mana_stream_mark(stream);
	}

	void ImageButton::onDeserialize(mana_stream* stream)
	{
		super::onDeserialize(stream);
		mana_stream_check(stream);
	}

	bool ImageButton::onDraw(const DrawRect& drawRect)
	{
		if(!super::onDraw(drawRect))
			return false;

		const int index = (getFrameStyle() & FRAME_STYLE_PUSHED || getEnable() == false) ? 1 : 0;
		if((frameTexture[0][index] == NULL) && (frameTexture[1][index] == NULL) && (frameTexture[2][index] == NULL))
			return false;

		Color baseColor = getDrawColor(drawRect, getColor());
		if(baseColor.a <= 0.0f)
			return false;

		GraphicDevice::setBlendMode(static_cast<GraphicDevice::BlendMode>(getBlendMode()));
		GraphicDevice::enableTexture(true);

		//////////////////////////////////////////////////////////////////////
		const Vector2 lt = drawRect.getDrawLeftTopPosition();
		const Vector2 rb = drawRect.getDrawRightBottomPosition();

		const float leftFrameSize = this->leftFrameSize * drawRect.scale.x;
		const float rightFrameSize = this->rightFrameSize * drawRect.scale.x;

		// 左頂点
		const Vector2 vltlt(lt.x                 , lt.y);	// 左上
		const Vector2 vltrt(lt.x + leftFrameSize , lt.y);	// 右上
		const Vector2 vltlb(lt.x                 , rb.y);	// 左下
		const Vector2 vltrb(lt.x + leftFrameSize , rb.y);	// 右下
		// 右頂点
		const Vector2 vrtlt(rb.x - rightFrameSize, lt.y);	// 左上
		const Vector2 vrtrt(rb.x                 , lt.y);	// 右上
		const Vector2 vrtlb(rb.x - rightFrameSize, rb.y);	// 左下
		const Vector2 vrtrb(rb.x                 , rb.y);	// 右下
		// 内部のサイズ
		const float frameWidth = vrtlt.x - vltrt.x;			// 幅
		const float frameHeight = vltlb.y - vltlt.y;		// 高さ

		//////////////////////////////////////////////////////////////////////
		// 描画
		drawFrame(frameTexture[0][index], frameTexCoord[0][index], vltrt, vrtlt, vltrb, vrtlb, baseColor, frameWidth, frameHeight);
		drawFrame(frameTexture[1][index], frameTexCoord[1][index], vltlt, vltrt, vltlb, vltrb, baseColor, leftFrameSize, frameHeight);
		drawFrame(frameTexture[2][index], frameTexCoord[2][index], vrtlt, vrtrt, vrtlb, vrtrb, baseColor, rightFrameSize, frameHeight);

		return true;
	}

	void ImageButton::drawFrame(Texture* texture, const Vector2& uv, const Vector2& v0, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Color& color, const float width, const float height)
	{
		if(texture)
		{
			texture->bind();

			const Vector2 textureSize = texture->getTextureSize();
			const Vector2 uv0((uv.x        ) / textureSize.x, (uv.y         ) / textureSize.y);
			const Vector2 uv1((uv.x + width) / textureSize.x, (uv.y         ) / textureSize.y);
			const Vector2 uv2((uv.x        ) / textureSize.x, (uv.y + height) / textureSize.y);
			const Vector2 uv3((uv.x + width) / textureSize.x, (uv.y + height) / textureSize.y);

			GraphicDevice::begin(GraphicDevice::TYPE_TEXTURE_COORDINATE, GraphicDevice::TRIANGLES, color);
			GraphicDevice::addTextureCoord(uv0);
			GraphicDevice::addTextureCoord(uv1);
			GraphicDevice::addTextureCoord(uv2);
			GraphicDevice::addTextureCoord(uv1);
			GraphicDevice::addTextureCoord(uv2);
			GraphicDevice::addTextureCoord(uv3);
			GraphicDevice::addVertex(v0);
			GraphicDevice::addVertex(v1);
			GraphicDevice::addVertex(v2);
			GraphicDevice::addVertex(v1);
			GraphicDevice::addVertex(v2);
			GraphicDevice::addVertex(v3);
			GraphicDevice::end();
		}
	}

	bool ImageButton::onTouchesBegan(const Vector2& localPosition)
	{
		// マウスをキャプチャー
		setMouseCapture();
		// 押されたアニメーションを開始
		// TODO
//		if(!setAnimation("push"))
		{
			// スタイルを押された状態に変更
			setFrameStyle(getFrameStyle() | FRAME_STYLE_PUSHED);
		}
		// 親クラスを実行
		return super::onTouchesBegan(localPosition);
	}

	bool ImageButton::onTouchesEnded(const Vector2& localPosition)
	{
		// マウスを解放
		Component::releaseMouseCapture();
		// 放したアニメーションを開始
		// TODO
		//if(!setAnimation("release"))
		{
			// スタイルを押されていない状態に戻す
			setFrameStyle(getFrameStyle() & ~FRAME_STYLE_PUSHED);
		}
		// クリックイベントを実行
		if(clickEvent)
		{
			clickEvent->onClick(this);
		}
		// 親クラスを実行
		return super::onTouchesEnded(localPosition) || clickEvent != NULL;
	}

	bool ImageButton::onTouchesCancelled(const Vector2& localPosition)
	{
		// マウスを解放
		Component::releaseMouseCapture();
		// 放したアニメーションを開始
		// TODO
		//if(!setAnimation("release"))
		{
			// スタイルを押されていない状態に戻す
			setFrameStyle(getFrameStyle() & ~FRAME_STYLE_PUSHED);
		}
		// 親クラスを実行
		return super::onTouchesCancelled(localPosition);
	}

	bool ImageButton::compare(const ImageButton& other) const
	{
		// 親クラスを実行
		if(!super::compare(other))
			return false;

		//ClickEvent* clickEvent;

		return true;
	}
}
